package com.imooc.sellspringcloud.server.controller;


import com.imooc.product.common.ProductInfoOutput;
import com.imooc.sellspringcloud.client.ProductClient;
import com.imooc.sellspringcloud.server.VO.ResultVO;
import com.imooc.sellspringcloud.server.conver.OrderConver;
import com.imooc.sellspringcloud.server.dataobject.OrderDetail;
import com.imooc.sellspringcloud.server.dto.OrderDTO;
import com.imooc.sellspringcloud.server.enums.OrderExceptionEnum;
import com.imooc.sellspringcloud.server.enums.OrderStatusEnum;
import com.imooc.sellspringcloud.server.exception.OrderException;
import com.imooc.sellspringcloud.server.form.OrderForm;
import com.imooc.sellspringcloud.server.mq.ProductMessage;
import com.imooc.sellspringcloud.server.redis.ProductKey;
import com.imooc.sellspringcloud.server.redis.RedisService;
import com.imooc.sellspringcloud.server.service.OrderService;
import com.imooc.sellspringcloud.server.utils.KeyUtil;
import com.imooc.sellspringcloud.server.utils.ResultVOUtil;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.util.HashMap;
import java.util.List;

/**
 * @author
 * @create 2019-07-27 21:59
 **/
@RestController
@Slf4j
public class OrderController implements InitializingBean {

    @Autowired
    private OrderService orderService;
    @Autowired
    private Person person;
    @Autowired
    ProductClient productClient;
    @Autowired
    RedisService redisService;
    @Autowired
    ProductMessage productMessage;

    public static HashMap<String, Boolean> localMap = new HashMap<>(20);

    /**
     * 加入本地标志，以及redis缓存中
     *
     * @throws Exception
     */
    @Override
    public void afterPropertiesSet() throws Exception {
        List<ProductInfoOutput> productList = productClient.getAllProductList();
        if (productList != null && productList.size() > 0) {
            for (ProductInfoOutput output : productList) {
                localMap.put(output.getProductId(), false);
                redisService.set(ProductKey.productListKey, output.getProductId(),
                        output.getProductStock());
            }
        }
    }


    @PostMapping("/createOrder")
    public ResultVO createOrder(@Validated OrderForm orderForm,
                                BindingResult bindingResult) {
        if (bindingResult.hasErrors()) {
            log.error("参数有误 {}", bindingResult.getFieldError().getDefaultMessage());
            throw new OrderException(OrderExceptionEnum.ORDER_ERROR.getCode(),
                    bindingResult.getFieldError().getDefaultMessage());
        }

        OrderDTO orderDTO = OrderConver.orderForm2OrderDTO(orderForm);
        if (CollectionUtils.isEmpty(orderDTO.getOrderDetailList())) {
            throw new OrderException(OrderExceptionEnum.ORDER_ERROR.getCode(), "商品ID为空，检查订单信息");
        }

        List<OrderDetail> detailList = orderDTO.getOrderDetailList();
        for (OrderDetail detail : detailList) {
            // javaHashMap 缓冲检查
            Boolean soldOut = localMap.get(detail.getProductId());
            if (soldOut) {
                throw new OrderException(OrderExceptionEnum.PRODUCT_STOACK.getCode(), "商品 " + detail.getProductName() + " 库存不足");
            }

            // redis 预减库存
            Long desc = redisService.desc(ProductKey.productListKey, detail.getProductId(), detail.getProductQuantity().longValue());
            if (desc < 0) {
                localMap.put(detail.getProductId(), true);
                throw new OrderException(OrderExceptionEnum.PRODUCT_STOACK.getCode(), "商品 " + detail.getProductName() + " 库存不足");
            }
        }
        // 入队
        String orderId = KeyUtil.genUniqueKey();
        orderDTO.setOrderId(orderId);
        productMessage.sendOrder(orderDTO);

        HashMap<String, Object> result = new HashMap<>();
        result.put("id", orderId);
        return ResultVOUtil.success(result);
    }

    @PostMapping("/finish")
    public ResultVO finishOrder(@RequestParam("orderId") String orderId) {
        orderService.changeOrderStatus(orderId, OrderStatusEnum.FINISHED.getStatus());
        return ResultVOUtil.success(true);
    }

    /*    @HystrixCommand(fallbackMethod = "fallback")
        @GetMapping("/getProductList")
        public ResultVO getProductList(@RequestParam("order") Integer order) {
            if (order % 2 == 0){
                List<ProductInfoOutput> allProductList = productClient.getAllProductList();
                return ResultVOUtil.success(allProductList);
            } else {
                throw new RuntimeException("服务异常");
            }
        }*/

    @HystrixCommand(commandProperties = {
            @HystrixProperty(name = "circuitBreaker.enabled", value = "true"),
            @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "10"),
            @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "10000"),
            @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "60")
    })
    @GetMapping("/getProductList")
    public ResultVO getProductList(@RequestParam("order") Integer order) {
        if (order % 2 == 0) {
            List<ProductInfoOutput> allProductList = productClient.getAllProductList();
            return ResultVOUtil.success(allProductList);
        } else {
            throw new RuntimeException("服务异常");
        }
    }

    private ResultVO fallback(Integer order) {
        return ResultVOUtil.fail("过于拥挤，请稍后再试");

    }

    @GetMapping("/print")
    public String getRefreshData() {
        java.lang.String str = "person";
        char c = str.charAt(0);
        log.info("name {}", person.getName());
        return person.toString();
    }

    @GetMapping(value = "/downFile", produces = {MediaType.APPLICATION_OCTET_STREAM_VALUE})
    public void downLoadFile(@RequestParam("fileUrl") String fileUrl) {
        ServletRequestAttributes requestAttributes =
                (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletResponse response = requestAttributes.getResponse();

        byte[] bytes = new byte[1024];
        int n = 0;
        int count = 0;
        InputStream inputStream = null;
        try {
            URL url = new URL(fileUrl);
            URLConnection urlConnection = url.openConnection();
            inputStream = urlConnection.getInputStream();
            while ((n = inputStream.read(bytes)) > 0) {
                response.getOutputStream().write(bytes, 0, n);
                count += n;
            }
            response.addHeader("Content-Length", String.valueOf(count));
            response.getOutputStream().flush();
            response.getOutputStream().close();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                inputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }


}